﻿// <copyright file="MembersOfCongress.cs" company="Microsoft Corporation">
// Copyright (c) 2009 Microsoft Corporation All Rights Reserved
// </copyright>
// <author>Michael S. Scherotter</author>
// <email>mischero@microsoft.com</email>
// <date>2009-04-30</date>
// <summary>MembersOfCongress CLR Class definition</summary>

namespace NYTimes
{
    using System;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Globalization;
    using System.Linq;
    using System.Text;
    using System.Xml.Linq;
    using NYTimes.Core;
    using NYTimes.Data;
    
    /// <summary>
    /// New York Times US Congress Member API
    /// </summary>
    public class MembersOfCongress : Core.CongressApi
    {
        #region Fields
        /// <summary>
        /// the congress number
        /// </summary>
        private int congressNumber;

        /// <summary>
        /// the chamber
        /// </summary>
        private Chamber chamber;

        /// <summary>
        /// the state (2-character abbreviation)
        /// </summary>
        private string state;

        /// <summary>
        /// the district (for house members)
        /// </summary>
        private int? district;

        #endregion

        #region Constructors
        /// <summary>
        /// Initializes a new instance of the MembersOfCongress class.
        /// </summary>
        public MembersOfCongress()
        {
            this.Members = new ObservableCollection<CongressMember>();

            if (SampleData.IsInDesignTool)
            {
                var xml = Core.SampleData.GetSampleData("MembersOfCongress.xml");

                if (!string.IsNullOrEmpty(xml))
                {
                    this.ParseXml(xml);
                }
            }
        }
        #endregion

        #region Properties
        /// <summary>
        /// Gets or sets the congress number
        /// </summary>
        [Description("Gets or sets the congress number")]
        public int CongressNumber 
        {
            get
            {
                return this.congressNumber;
            }

            set
            {
                if (this.congressNumber != value)
                {
                    if (value > 0)
                    {
                        this.congressNumber = value;

                        this.FetchResults();
                    }
                }
            }
        }

        /// <summary>
        /// Gets or sets the chamber
        /// </summary>
        [Description("Gets or sets the chamber (house or senate)")]
        public Chamber Chamber 
        {
            get
            {
                return this.chamber;
            }

            set
            {
                if (this.chamber != value)
                {
                    this.chamber = value;

                    this.FetchResults();
                }
            }
        }

        /// <summary>
        /// Gets or sets the 2-character state abbreviation
        /// </summary>
        [Description("Gets or sets the 2-character state abbreviation")]
        public string State
        {
            get
            {
                return this.state;
            }

            set
            {
                if (this.state != value)
                {
                    this.state = value;

                    this.FetchResults();
                }
            }
        }

        /// <summary>
        /// Gets or sets the district number for House of Representatives.
        /// </summary>
        [Description("Gets or sets the district number for House of Representatives.")]
        public int? District 
        {
            get
            {
                return this.district;
            }

            set
            {
                if (this.district != value)
                {
                    if (value < 1)
                    {
                        return;
                    }

                    this.district = value;

                    this.FetchResults();
                }
            }
        }

        /// <summary>
        /// Gets the members of a specific congress
        /// </summary>
        public ObservableCollection<CongressMember> Members { get; private set; }

        #endregion

        #region Methods
        /// <summary>
        /// determines whether the state is valid to fetch results
        /// </summary>
        /// <returns>true if the CongressNumber is greater than 0</returns>
        public override bool ShouldFetchResults()
        {
            return this.CongressNumber > 0;
        }

        /// <summary>
        /// Clear the Members
        /// </summary>
        public override void ClearResults()
        {
            this.Members.Clear();
        }

        /// <summary>
        /// Parse the members
        /// </summary>
        /// <param name="results">the XML results</param>
        public override void OnParseResults(XElement results)
        {
            if (results == null)
            {
                throw new ArgumentNullException("results");
            }

            var members = from member in results.Element("members").Elements("member")
                          select new CongressMember()
                          {
                              Id = member.Element("id").Value,
                              ApiUri = new Uri(member.Element("api_uri").Value, UriKind.Absolute),
                              FirstName = member.Element("first_name").Value,
                              MiddleName = member.Element("middle_name").Value,
                              LastName = member.Element("last_name").Value,
                              Party = member.Element("party").Value,
                              State = member.Element("state").Value,
                              Seniority = int.Parse(member.Element("seniority").Value, CultureInfo.InvariantCulture),
                              NextElection = member.Element("next_election") == null ? new int?() : int.Parse(member.Element("next_election").Value, CultureInfo.InvariantCulture),
                              District = (member.Element("district") == null) ? new int?() : int.Parse(member.Element("district").Value, CultureInfo.InvariantCulture),
                              MissedVotePercent = member.Element("missed_votes_pct") == null ? 0 : float.Parse(member.Element("missed_votes_pct").Value, CultureInfo.InvariantCulture),
                              VotesWithPartyPercent = member.Element("votes_with_party_pct") == null ? 0 : float.Parse(member.Element("votes_with_party_pct").Value, CultureInfo.InvariantCulture)
                          };

            foreach (var member in members)
            {
                this.Members.Add(member);
            }
        }
        #endregion

        #region Implementation

        /// <summary>
        /// Generate the URI
        /// </summary>
        /// <param name="baseUri">the base URI</param>
        /// <returns>the REST URL</returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1304:SpecifyCultureInfo", MessageId = "System.String.ToLower", Justification = "Irrelevant for Silverlight.")]
        public override Uri GenerateUrl(string baseUri)
        {
            var builder = new StringBuilder(baseUri);

            builder.AppendFormat(
                CultureInfo.InvariantCulture,
                "/{0}/{1}/members.xml?",
                this.CongressNumber,
                this.Chamber.ToString().ToLower());

            if (!string.IsNullOrEmpty(this.State))
            {
                builder.AppendFormat(
                    CultureInfo.InvariantCulture,
                    "state={0}",
                    this.State);

                if (this.District.HasValue && this.Chamber == Chamber.House)
                {
                    builder.AppendFormat(
                        CultureInfo.InvariantCulture,
                        "&district={0}",
                        this.District);
                }
            }

            if (!builder.ToString().EndsWith("?", StringComparison.OrdinalIgnoreCase))
            {
                builder.Append("&");
            }

            builder.AppendFormat(
                CultureInfo.InvariantCulture,
                "api-key={0}", 
                this.ApiKey);

            return new Uri(builder.ToString(), UriKind.Absolute);
        }
        #endregion
    }
}
